# pragma once

# include<deque>
# include<Arduino.h>
# include"../ganix/pwm.h"

class AbstructOutputPin {
    public:
    String name;
    virtual void set_state(int state) = 0;
    virtual void set_pwm(float pwm) = 0;
    virtual int get_state() = 0;
    String get_name() { return name; };
};


class Esp8266OutputPin: public AbstructOutputPin {
    int state;
    float pwm;
    int phy_pin;
    public:
    Esp8266OutputPin(int _phy_pin, String _name = ""): state(0), pwm(0), phy_pin(_phy_pin) {
        pinMode(phy_pin, OUTPUT);
        digitalWrite(phy_pin, 0);
        if (_name == "") {
            name = "8266-" + String(_phy_pin);
        } else {
            name = _name;
        }
    }

    void set_state(int sw) {
        if (sw == -1) {
            state = 1 - state;
        } else {
            state = sw;
        }
        digitalWrite(phy_pin, state);
    }

    int get_state() {
        return state;
    }

    void set_pwm(float rate) {
        if (fabs(pwm - rate) > 1e-3) {
            pwm = rate;
        } else {
            pwm = 0;
        }
        ganix::pwm::init();
        ganix::pwm::set_rate(phy_pin, pwm);
    }

    bool match(String pin_name) {
        return pin_name == name;
    }
};


class PinGroup
{
    private:
    std::deque<AbstructOutputPin* > member;
    int state = 1; // 默认状态下，所有灯都关着，按一下就都打开
    std::deque<int> memory;
    String name;

    void set_state(int sw) {
        state = sw == -1 ? 1 - state : sw;
        if (state == 0) { // 记录当前灯光状态，关闭所有灯
            memory.resize(member.size());
            for (int i = 0; i < member.size(); i++) {
                memory[i] = member[i]->get_state();
                member[i]->set_state(0);
            }
        } if (state == 1) { // 根据记录回复灯光状态
            for (int i = 0; i < member.size(); i++) {
                int flag = i < memory.size() ? memory[i] : 1; // 如果没有记录，就直接打开
                member[i]->set_state(flag);
            }
        }
    }
    public:
    PinGroup(String _name) : name(_name) {};

    void accept(String name, int sw) { // 有accept动作
        for (auto *m : member) {
            if (m->get_name() == name) { // 组内有灯变化了，重置组状态
                state = 1;
            }
        }
        if (this->name == name) {
            set_state(sw);
        }
    }

    void add_member(AbstructOutputPin* m) {
        member.push_back(m);
    }
};

std::deque<AbstructOutputPin* > output_pin_list;
std::deque<PinGroup> output_pin_group;

void accept_pin_sw(String pin_name, int sw) {
    for (AbstructOutputPin* pin : output_pin_list) {
        if (pin->get_name() == pin_name) {
            pin->set_state(sw);
            break;
        }
    }
    for (PinGroup group : output_pin_group) {
        group.accept(pin_name, sw);
    }
}

void accept_pin_pwm(String pin_name, float rate) {
    for (AbstructOutputPin* pin : output_pin_list) {
        if (pin->get_name() == pin_name) {
            pin->set_pwm(rate);
            break;
        }
    }
}
